"use server";

import {
    ACHClass,
    CountryCode,
    TransferAuthorizationCreateRequest,
    TransferCreateRequest,
    TransferNetwork,
    TransferType,
} from "plaid";


import { parseStringify } from "../utils";

import { getTransactionsByBankId } from "./transaction.actions";
import { getBanks, getBank } from "./user.actions";
import {plaidClient} from "@/lib/plaid";

// Get multiple bank accounts
export const getAccounts = async ({ userId }: getAccountsProps) => {
    try {
        // get banks from db
        const banks = await getBanks({ userId });

        const accounts = await Promise.all(
            banks?.map(async (bank: Bank) => {
                // get each account info from plaid
                const accountsResponse = await plaidClient.accountsGet({
                    access_token: bank.accessToken,
                });
                const accountData = accountsResponse.data.accounts[0];

                // get institution info from plaid
                const institution = await getInstitution({
                    institutionId: accountsResponse.data.item.institution_id!,
                });

                const account = {
                    id: accountData.account_id,
                    availableBalance: accountData.balances.available!,
                    currentBalance: accountData.balances.current!,
                    institutionId: institution.institution_id,
                    name: accountData.name,
                    officialName: accountData.official_name,
                    mask: accountData.mask!,
                    type: accountData.type as string,
                    subtype: accountData.subtype! as string,
                    appwriteItemId: bank.$id,
                    shareableId: bank.shareableId,
                };

                return account;
            })
        );

        const totalBanks = accounts.length;
        const totalCurrentBalance = accounts.reduce((total, account) => {
            return total + account.currentBalance;
        }, 0);

        return parseStringify({ data: accounts, totalBanks, totalCurrentBalance });
    } catch (error) {
        console.error("An error occurred while getting the accounts:", error);
    }
};


// Get one bank account
export const getAccount = async ({ appwriteItemId }: getAccountProps) => {
    try {
        // get bank from db
        const bank = await getBank({ documentId: appwriteItemId });

        if (!bank) {
            throw new Error("Bank not found");
        }

        // get account info from plaid
        const accountsResponse = await plaidClient.accountsGet({
            access_token: bank.accessToken,
            
        });
        
        const accountData = accountsResponse.data.accounts[0];
      

        if (!accountData) {
            throw new Error("Account data not found");
        }

        // get transfer transactions from appwrite
        const transferTransactionsData = await getTransactionsByBankId({
            bankId: bank.$id,
        });

        const transferTransactions = transferTransactionsData.documents.map(
            (transferData: Transaction) => ({
                id: transferData.$id,
                name: transferData.name!,
                amount: transferData.amount!,
                date: transferData.$createdAt,
                paymentChannel: transferData.channel,
                category: transferData.category,
                // 使用金额和银行ID来判断交易类型
                type: transferData.amount < 0 ? "debit" : "credit",
            })
        );

        // get institution info from plaid
        const institution = await getInstitution({
            institutionId: accountsResponse.data.item.institution_id!,
        });

        const transactions = await getTransactions({
            accessToken: bank?.accessToken,
        });

        const account = {
            id: accountData.account_id,
            availableBalance: accountData.balances.available!,
            currentBalance: accountData.balances.current!,
            institutionId: institution.institution_id,
            name: accountData.name,
            officialName: accountData.official_name,
            mask: accountData.mask!,
            type: accountData.type as string,
            subtype: accountData.subtype! as string,
            appwriteItemId: bank.$id,
        };

        // sort transactions by date such that the most recent transaction is first
        const allTransactions = [...transactions, ...transferTransactions].sort(
            (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
        );

        return parseStringify({
            data: account,
            transactions: allTransactions,
        });
    } catch (error) {
        console.error("错误，请及时修改", error);
        return null; // 明确返回 null 表示没有获取到账户信息
    }
};

// Get bank info
export const getInstitution = async ({
                                         institutionId,
                                     }: getInstitutionProps) => {
    try {
        const institutionResponse = await plaidClient.institutionsGetById({
            institution_id: institutionId,
            country_codes: ["US"] as CountryCode[],
        });

        const intitution = institutionResponse.data.institution;

        return parseStringify(intitution);
    } catch (error) {
        console.error("An error occurred while getting the accounts:", error);
    }
};

// Get transactions
export const getTransactions = async ({
                                          accessToken,
                                      }: getTransactionsProps) => {
    let hasMore = true;
    let transactions: any = [];

    try {
        // Iterate through each page of new transaction updates for item
        while (hasMore) {
            const response = await plaidClient.transactionsSync({
                access_token: accessToken,
            });

            const data = response.data;

            transactions = response.data.added.map((transaction) => ({
                id: transaction.transaction_id,
                name: transaction.name,
                paymentChannel: transaction.payment_channel,
                type: transaction.payment_channel,
                accountId: transaction.account_id,
                amount: transaction.amount,
                pending: transaction.pending,
                category: transaction.category ? transaction.category[0] : "",
                date: transaction.date,
                image: transaction.logo_url,
            }));

            hasMore = data.has_more;
        }

        return parseStringify(transactions);
    } catch (error) {
        console.error("An error occurred while getting the accounts:", error);
    }
};

// Create Transfer
export const createTransfer = async () => {
    const transferAuthRequest: TransferAuthorizationCreateRequest = {
        access_token: "access-sandbox-cddd20c1-5ba8-4193-89f9-3a0b91034c25",
        account_id: "Zl8GWV1jqdTgjoKnxQn1HBxxVBanm5FxZpnQk",
        funding_account_id: "442d857f-fe69-4de2-a550-0c19dc4af467",
        type: "credit" as TransferType,
        network: "ach" as TransferNetwork,
        amount: "10.00",
        ach_class: "ppd" as ACHClass,
        user: {
            legal_name: "Anne Charleston",
        },
    };
    try {
        const transferAuthResponse =
            await plaidClient.transferAuthorizationCreate(transferAuthRequest);
        const authorizationId = transferAuthResponse.data.authorization.id;

        const transferCreateRequest: TransferCreateRequest = {
            access_token: "access-sandbox-cddd20c1-5ba8-4193-89f9-3a0b91034c25",
            account_id: "Zl8GWV1jqdTgjoKnxQn1HBxxVBanm5FxZpnQk",
            description: "payment",
            authorization_id: authorizationId,
        };

        const responseCreateResponse = await plaidClient.transferCreate(
            transferCreateRequest
        );

        const transfer = responseCreateResponse.data.transfer;
        return parseStringify(transfer);
    } catch (error) {
        console.error(
            "An error occurred while creating transfer authorization:",
            error
        );
    }
};